home *** CD-ROM | disk | FTP | other *** search
/ Chip 2007 January, February, March & April / Chip-Cover-CD-2007-02.iso / Pakiet bezpieczenstwa / mini Pentoo LiveCD 2006.1 / mpentoo-2006.1.iso / livecd.squashfs / usr / lib / python2.4 / aifc.pyo (.txt) < prev    next >
Python Compiled Bytecode  |  2005-10-18  |  29KB  |  1,040 lines

  1. # Source Generated with Decompyle++
  2. # File: in.pyo (Python 2.4)
  3.  
  4. '''Stuff to parse AIFF-C and AIFF files.
  5.  
  6. Unless explicitly stated otherwise, the description below is true
  7. both for AIFF-C files and AIFF files.
  8.  
  9. An AIFF-C file has the following structure.
  10.  
  11.   +-----------------+
  12.   | FORM            |
  13.   +-----------------+
  14.   | <size>          |
  15.   +----+------------+
  16.   |    | AIFC       |
  17.   |    +------------+
  18.   |    | <chunks>   |
  19.   |    |    .       |
  20.   |    |    .       |
  21.   |    |    .       |
  22.   +----+------------+
  23.  
  24. An AIFF file has the string "AIFF" instead of "AIFC".
  25.  
  26. A chunk consists of an identifier (4 bytes) followed by a size (4 bytes,
  27. big endian order), followed by the data.  The size field does not include
  28. the size of the 8 byte header.
  29.  
  30. The following chunk types are recognized.
  31.  
  32.   FVER
  33.       <version number of AIFF-C defining document> (AIFF-C only).
  34.   MARK
  35.       <# of markers> (2 bytes)
  36.       list of markers:
  37.           <marker ID> (2 bytes, must be > 0)
  38.           <position> (4 bytes)
  39.           <marker name> ("pstring")
  40.   COMM
  41.       <# of channels> (2 bytes)
  42.       <# of sound frames> (4 bytes)
  43.       <size of the samples> (2 bytes)
  44.       <sampling frequency> (10 bytes, IEEE 80-bit extended
  45.           floating point)
  46.       in AIFF-C files only:
  47.       <compression type> (4 bytes)
  48.       <human-readable version of compression type> ("pstring")
  49.   SSND
  50.       <offset> (4 bytes, not used by this program)
  51.       <blocksize> (4 bytes, not used by this program)
  52.       <sound data>
  53.  
  54. A pstring consists of 1 byte length, a string of characters, and 0 or 1
  55. byte pad to make the total length even.
  56.  
  57. Usage.
  58.  
  59. Reading AIFF files:
  60.   f = aifc.open(file, \'r\')
  61. where file is either the name of a file or an open file pointer.
  62. The open file pointer must have methods read(), seek(), and close().
  63. In some types of audio files, if the setpos() method is not used,
  64. the seek() method is not necessary.
  65.  
  66. This returns an instance of a class with the following public methods:
  67.   getnchannels()  -- returns number of audio channels (1 for
  68.              mono, 2 for stereo)
  69.   getsampwidth()  -- returns sample width in bytes
  70.   getframerate()  -- returns sampling frequency
  71.   getnframes()    -- returns number of audio frames
  72.   getcomptype()   -- returns compression type (\'NONE\' for AIFF files)
  73.   getcompname()   -- returns human-readable version of
  74.              compression type (\'not compressed\' for AIFF files)
  75.   getparams() -- returns a tuple consisting of all of the
  76.              above in the above order
  77.   getmarkers()    -- get the list of marks in the audio file or None
  78.              if there are no marks
  79.   getmark(id) -- get mark with the specified id (raises an error
  80.              if the mark does not exist)
  81.   readframes(n)   -- returns at most n frames of audio
  82.   rewind()    -- rewind to the beginning of the audio stream
  83.   setpos(pos) -- seek to the specified position
  84.   tell()      -- return the current position
  85.   close()     -- close the instance (make it unusable)
  86. The position returned by tell(), the position given to setpos() and
  87. the position of marks are all compatible and have nothing to do with
  88. the actual position in the file.
  89. The close() method is called automatically when the class instance
  90. is destroyed.
  91.  
  92. Writing AIFF files:
  93.   f = aifc.open(file, \'w\')
  94. where file is either the name of a file or an open file pointer.
  95. The open file pointer must have methods write(), tell(), seek(), and
  96. close().
  97.  
  98. This returns an instance of a class with the following public methods:
  99.   aiff()      -- create an AIFF file (AIFF-C default)
  100.   aifc()      -- create an AIFF-C file
  101.   setnchannels(n) -- set the number of channels
  102.   setsampwidth(n) -- set the sample width
  103.   setframerate(n) -- set the frame rate
  104.   setnframes(n)   -- set the number of frames
  105.   setcomptype(type, name)
  106.           -- set the compression type and the
  107.              human-readable compression type
  108.   setparams(tuple)
  109.           -- set all parameters at once
  110.   setmark(id, pos, name)
  111.           -- add specified mark to the list of marks
  112.   tell()      -- return current position in output file (useful
  113.              in combination with setmark())
  114.   writeframesraw(data)
  115.           -- write audio frames without pathing up the
  116.              file header
  117.   writeframes(data)
  118.           -- write audio frames and patch up the file header
  119.   close()     -- patch up the file header and close the
  120.              output file
  121. You should set the parameters before the first writeframesraw or
  122. writeframes.  The total number of frames does not need to be set,
  123. but when it is set to the correct value, the header does not have to
  124. be patched up.
  125. It is best to first set all parameters, perhaps possibly the
  126. compression type, and then write audio frames using writeframesraw.
  127. When all frames have been written, either call writeframes(\'\') or
  128. close() to patch up the sizes in the header.
  129. Marks can be added anytime.  If there are any marks, ypu must call
  130. close() after all frames have been written.
  131. The close() method is called automatically when the class instance
  132. is destroyed.
  133.  
  134. When a file is opened with the extension \'.aiff\', an AIFF file is
  135. written, otherwise an AIFF-C file is written.  This default can be
  136. changed by calling aiff() or aifc() before the first writeframes or
  137. writeframesraw.
  138. '''
  139. import struct
  140. import __builtin__
  141. __all__ = [
  142.     'Error',
  143.     'open',
  144.     'openfp']
  145.  
  146. class Error(Exception):
  147.     pass
  148.  
  149. _AIFC_version = 0xA2805140L
  150. _skiplist = ('COMT', 'INST', 'MIDI', 'AESD', 'APPL', 'NAME', 'AUTH', '(c) ', 'ANNO')
  151.  
  152. def _read_long(file):
  153.     
  154.     try:
  155.         return struct.unpack('>l', file.read(4))[0]
  156.     except struct.error:
  157.         raise EOFError
  158.  
  159.  
  160.  
  161. def _read_ulong(file):
  162.     
  163.     try:
  164.         return struct.unpack('>L', file.read(4))[0]
  165.     except struct.error:
  166.         raise EOFError
  167.  
  168.  
  169.  
  170. def _read_short(file):
  171.     
  172.     try:
  173.         return struct.unpack('>h', file.read(2))[0]
  174.     except struct.error:
  175.         raise EOFError
  176.  
  177.  
  178.  
  179. def _read_string(file):
  180.     length = ord(file.read(1))
  181.     if length == 0:
  182.         data = ''
  183.     else:
  184.         data = file.read(length)
  185.     if length & 1 == 0:
  186.         dummy = file.read(1)
  187.     
  188.     return data
  189.  
  190. _HUGE_VAL = 1.7976931348623099e+308
  191.  
  192. def _read_float(f):
  193.     expon = _read_short(f)
  194.     sign = 1
  195.     if expon < 0:
  196.         sign = -1
  197.         expon = expon + 32768
  198.     
  199.     himant = _read_ulong(f)
  200.     lomant = _read_ulong(f)
  201.     if himant == himant and lomant == lomant:
  202.         pass
  203.     elif lomant == 0:
  204.         f = 0.0
  205.     elif expon == 32767:
  206.         f = _HUGE_VAL
  207.     else:
  208.         expon = expon - 16383
  209.         f = (himant * 0x100000000L + lomant) * pow(2.0, expon - 63)
  210.     return sign * f
  211.  
  212.  
  213. def _write_short(f, x):
  214.     f.write(struct.pack('>h', x))
  215.  
  216.  
  217. def _write_long(f, x):
  218.     f.write(struct.pack('>L', x))
  219.  
  220.  
  221. def _write_string(f, s):
  222.     f.write(chr(len(s)))
  223.     f.write(s)
  224.     if len(s) & 1 == 0:
  225.         f.write(chr(0))
  226.     
  227.  
  228.  
  229. def _write_float(f, x):
  230.     import math as math
  231.     if x < 0:
  232.         sign = 32768
  233.         x = x * -1
  234.     else:
  235.         sign = 0
  236.     if x == 0:
  237.         expon = 0
  238.         himant = 0
  239.         lomant = 0
  240.     else:
  241.         (fmant, expon) = math.frexp(x)
  242.         if expon > 16384 or fmant >= 1:
  243.             expon = sign | 32767
  244.             himant = 0
  245.             lomant = 0
  246.         else:
  247.             expon = expon + 16382
  248.             if expon < 0:
  249.                 fmant = math.ldexp(fmant, expon)
  250.                 expon = 0
  251.             
  252.             expon = expon | sign
  253.             fmant = math.ldexp(fmant, 32)
  254.             fsmant = math.floor(fmant)
  255.             himant = long(fsmant)
  256.             fmant = math.ldexp(fmant - fsmant, 32)
  257.             fsmant = math.floor(fmant)
  258.             lomant = long(fsmant)
  259.     _write_short(f, expon)
  260.     _write_long(f, himant)
  261.     _write_long(f, lomant)
  262.  
  263. from chunk import Chunk
  264.  
  265. class Aifc_read:
  266.     
  267.     def initfp(self, file):
  268.         self._version = 0
  269.         self._decomp = None
  270.         self._convert = None
  271.         self._markers = []
  272.         self._soundpos = 0
  273.         self._file = Chunk(file)
  274.         if self._file.getname() != 'FORM':
  275.             raise Error, 'file does not start with FORM id'
  276.         
  277.         formdata = self._file.read(4)
  278.         if formdata == 'AIFF':
  279.             self._aifc = 0
  280.         elif formdata == 'AIFC':
  281.             self._aifc = 1
  282.         else:
  283.             raise Error, 'not an AIFF or AIFF-C file'
  284.         self._comm_chunk_read = 0
  285.         while None:
  286.             self._ssnd_seek_needed = 1
  287.             
  288.             try:
  289.                 chunk = Chunk(self._file)
  290.             except EOFError:
  291.                 break
  292.  
  293.             chunkname = chunk.getname()
  294.             if chunkname == 'COMM':
  295.                 self._read_comm_chunk(chunk)
  296.                 self._comm_chunk_read = 1
  297.             elif chunkname == 'SSND':
  298.                 self._ssnd_chunk = chunk
  299.                 dummy = chunk.read(8)
  300.                 self._ssnd_seek_needed = 0
  301.             elif chunkname == 'FVER':
  302.                 self._version = _read_ulong(chunk)
  303.             elif chunkname == 'MARK':
  304.                 self._readmark(chunk)
  305.             elif chunkname in _skiplist:
  306.                 pass
  307.             else:
  308.                 raise Error, 'unrecognized chunk type ' + chunk.chunkname
  309.         if not (self._comm_chunk_read) or not (self._ssnd_chunk):
  310.             raise Error, 'COMM chunk and/or SSND chunk missing'
  311.         
  312.         if self._aifc and self._decomp:
  313.             import cl as cl
  314.             params = [
  315.                 cl.ORIGINAL_FORMAT,
  316.                 0,
  317.                 cl.BITS_PER_COMPONENT,
  318.                 self._sampwidth * 8,
  319.                 cl.FRAME_RATE,
  320.                 self._framerate]
  321.             if self._nchannels == 1:
  322.                 params[1] = cl.MONO
  323.             elif self._nchannels == 2:
  324.                 params[1] = cl.STEREO_INTERLEAVED
  325.             else:
  326.                 raise Error, 'cannot compress more than 2 channels'
  327.             self._decomp.SetParams(params)
  328.         
  329.  
  330.     
  331.     def __init__(self, f):
  332.         if type(f) == type(''):
  333.             f = __builtin__.open(f, 'rb')
  334.         
  335.         self.initfp(f)
  336.  
  337.     
  338.     def getfp(self):
  339.         return self._file
  340.  
  341.     
  342.     def rewind(self):
  343.         self._ssnd_seek_needed = 1
  344.         self._soundpos = 0
  345.  
  346.     
  347.     def close(self):
  348.         if self._decomp:
  349.             self._decomp.CloseDecompressor()
  350.             self._decomp = None
  351.         
  352.         self._file = None
  353.  
  354.     
  355.     def tell(self):
  356.         return self._soundpos
  357.  
  358.     
  359.     def getnchannels(self):
  360.         return self._nchannels
  361.  
  362.     
  363.     def getnframes(self):
  364.         return self._nframes
  365.  
  366.     
  367.     def getsampwidth(self):
  368.         return self._sampwidth
  369.  
  370.     
  371.     def getframerate(self):
  372.         return self._framerate
  373.  
  374.     
  375.     def getcomptype(self):
  376.         return self._comptype
  377.  
  378.     
  379.     def getcompname(self):
  380.         return self._compname
  381.  
  382.     
  383.     def getparams(self):
  384.         return (self.getnchannels(), self.getsampwidth(), self.getframerate(), self.getnframes(), self.getcomptype(), self.getcompname())
  385.  
  386.     
  387.     def getmarkers(self):
  388.         if len(self._markers) == 0:
  389.             return None
  390.         
  391.         return self._markers
  392.  
  393.     
  394.     def getmark(self, id):
  395.         for marker in self._markers:
  396.             if id == marker[0]:
  397.                 return marker
  398.                 continue
  399.         
  400.         raise Error, 'marker %r does not exist' % (id,)
  401.  
  402.     
  403.     def setpos(self, pos):
  404.         if pos < 0 or pos > self._nframes:
  405.             raise Error, 'position not in range'
  406.         
  407.         self._soundpos = pos
  408.         self._ssnd_seek_needed = 1
  409.  
  410.     
  411.     def readframes(self, nframes):
  412.         if self._ssnd_seek_needed:
  413.             self._ssnd_chunk.seek(0)
  414.             dummy = self._ssnd_chunk.read(8)
  415.             pos = self._soundpos * self._framesize
  416.             if pos:
  417.                 self._ssnd_chunk.seek(pos + 8)
  418.             
  419.             self._ssnd_seek_needed = 0
  420.         
  421.         if nframes == 0:
  422.             return ''
  423.         
  424.         data = self._ssnd_chunk.read(nframes * self._framesize)
  425.         if self._convert and data:
  426.             data = self._convert(data)
  427.         
  428.         self._soundpos = self._soundpos + len(data) / self._nchannels * self._sampwidth
  429.         return data
  430.  
  431.     
  432.     def _decomp_data(self, data):
  433.         import cl
  434.         dummy = self._decomp.SetParam(cl.FRAME_BUFFER_SIZE, len(data) * 2)
  435.         return self._decomp.Decompress(len(data) / self._nchannels, data)
  436.  
  437.     
  438.     def _ulaw2lin(self, data):
  439.         import audioop as audioop
  440.         return audioop.ulaw2lin(data, 2)
  441.  
  442.     
  443.     def _adpcm2lin(self, data):
  444.         import audioop
  445.         if not hasattr(self, '_adpcmstate'):
  446.             self._adpcmstate = None
  447.         
  448.         (data, self._adpcmstate) = audioop.adpcm2lin(data, 2, self._adpcmstate)
  449.         return data
  450.  
  451.     
  452.     def _read_comm_chunk(self, chunk):
  453.         self._nchannels = _read_short(chunk)
  454.         self._nframes = _read_long(chunk)
  455.         self._sampwidth = (_read_short(chunk) + 7) / 8
  456.         self._framerate = int(_read_float(chunk))
  457.         self._framesize = self._nchannels * self._sampwidth
  458.         if self._aifc:
  459.             kludge = 0
  460.             if chunk.chunksize == 18:
  461.                 kludge = 1
  462.                 print 'Warning: bad COMM chunk size'
  463.                 chunk.chunksize = 23
  464.             
  465.             self._comptype = chunk.read(4)
  466.             if kludge:
  467.                 length = ord(chunk.file.read(1))
  468.                 if length & 1 == 0:
  469.                     length = length + 1
  470.                 
  471.                 chunk.chunksize = chunk.chunksize + length
  472.                 chunk.file.seek(-1, 1)
  473.             
  474.             self._compname = _read_string(chunk)
  475.             if self._comptype != 'NONE':
  476.                 if self._comptype == 'G722':
  477.                     
  478.                     try:
  479.                         import audioop
  480.                     except ImportError:
  481.                         pass
  482.  
  483.                     self._convert = self._adpcm2lin
  484.                     self._framesize = self._framesize / 4
  485.                     return None
  486.                 
  487.                 
  488.                 try:
  489.                     import cl
  490.                 except ImportError:
  491.                     if self._comptype == 'ULAW':
  492.                         
  493.                         try:
  494.                             import audioop
  495.                             self._convert = self._ulaw2lin
  496.                             self._framesize = self._framesize / 2
  497.                             return None
  498.                         except ImportError:
  499.                             pass
  500.                         except:
  501.                             None<EXCEPTION MATCH>ImportError
  502.                         
  503.  
  504.                     None<EXCEPTION MATCH>ImportError
  505.                     raise Error, 'cannot read compressed AIFF-C files'
  506.  
  507.                 if self._comptype == 'ULAW':
  508.                     scheme = cl.G711_ULAW
  509.                     self._framesize = self._framesize / 2
  510.                 elif self._comptype == 'ALAW':
  511.                     scheme = cl.G711_ALAW
  512.                     self._framesize = self._framesize / 2
  513.                 else:
  514.                     raise Error, 'unsupported compression type'
  515.                 self._decomp = cl.OpenDecompressor(scheme)
  516.                 self._convert = self._decomp_data
  517.             
  518.         else:
  519.             self._comptype = 'NONE'
  520.             self._compname = 'not compressed'
  521.  
  522.     
  523.     def _readmark(self, chunk):
  524.         nmarkers = _read_short(chunk)
  525.         
  526.         try:
  527.             for i in range(nmarkers):
  528.                 id = _read_short(chunk)
  529.                 pos = _read_long(chunk)
  530.                 name = _read_string(chunk)
  531.                 if pos or name:
  532.                     self._markers.append((id, pos, name))
  533.                     continue
  534.         except EOFError:
  535.             print 'Warning: MARK chunk contains only', len(self._markers),
  536.             if len(self._markers) == 1:
  537.                 print 'marker',
  538.             else:
  539.                 print 'markers',
  540.             print 'instead of', nmarkers
  541.  
  542.  
  543.  
  544.  
  545. class Aifc_write:
  546.     
  547.     def __init__(self, f):
  548.         if type(f) == type(''):
  549.             filename = f
  550.             f = __builtin__.open(f, 'wb')
  551.         else:
  552.             filename = '???'
  553.         self.initfp(f)
  554.         if filename[-5:] == '.aiff':
  555.             self._aifc = 0
  556.         else:
  557.             self._aifc = 1
  558.  
  559.     
  560.     def initfp(self, file):
  561.         self._file = file
  562.         self._version = _AIFC_version
  563.         self._comptype = 'NONE'
  564.         self._compname = 'not compressed'
  565.         self._comp = None
  566.         self._convert = None
  567.         self._nchannels = 0
  568.         self._sampwidth = 0
  569.         self._framerate = 0
  570.         self._nframes = 0
  571.         self._nframeswritten = 0
  572.         self._datawritten = 0
  573.         self._datalength = 0
  574.         self._markers = []
  575.         self._marklength = 0
  576.         self._aifc = 1
  577.  
  578.     
  579.     def __del__(self):
  580.         if self._file:
  581.             self.close()
  582.         
  583.  
  584.     
  585.     def aiff(self):
  586.         if self._nframeswritten:
  587.             raise Error, 'cannot change parameters after starting to write'
  588.         
  589.         self._aifc = 0
  590.  
  591.     
  592.     def aifc(self):
  593.         if self._nframeswritten:
  594.             raise Error, 'cannot change parameters after starting to write'
  595.         
  596.         self._aifc = 1
  597.  
  598.     
  599.     def setnchannels(self, nchannels):
  600.         if self._nframeswritten:
  601.             raise Error, 'cannot change parameters after starting to write'
  602.         
  603.         if nchannels < 1:
  604.             raise Error, 'bad # of channels'
  605.         
  606.         self._nchannels = nchannels
  607.  
  608.     
  609.     def getnchannels(self):
  610.         if not self._nchannels:
  611.             raise Error, 'number of channels not set'
  612.         
  613.         return self._nchannels
  614.  
  615.     
  616.     def setsampwidth(self, sampwidth):
  617.         if self._nframeswritten:
  618.             raise Error, 'cannot change parameters after starting to write'
  619.         
  620.         if sampwidth < 1 or sampwidth > 4:
  621.             raise Error, 'bad sample width'
  622.         
  623.         self._sampwidth = sampwidth
  624.  
  625.     
  626.     def getsampwidth(self):
  627.         if not self._sampwidth:
  628.             raise Error, 'sample width not set'
  629.         
  630.         return self._sampwidth
  631.  
  632.     
  633.     def setframerate(self, framerate):
  634.         if self._nframeswritten:
  635.             raise Error, 'cannot change parameters after starting to write'
  636.         
  637.         if framerate <= 0:
  638.             raise Error, 'bad frame rate'
  639.         
  640.         self._framerate = framerate
  641.  
  642.     
  643.     def getframerate(self):
  644.         if not self._framerate:
  645.             raise Error, 'frame rate not set'
  646.         
  647.         return self._framerate
  648.  
  649.     
  650.     def setnframes(self, nframes):
  651.         if self._nframeswritten:
  652.             raise Error, 'cannot change parameters after starting to write'
  653.         
  654.         self._nframes = nframes
  655.  
  656.     
  657.     def getnframes(self):
  658.         return self._nframeswritten
  659.  
  660.     
  661.     def setcomptype(self, comptype, compname):
  662.         if self._nframeswritten:
  663.             raise Error, 'cannot change parameters after starting to write'
  664.         
  665.         if comptype not in ('NONE', 'ULAW', 'ALAW', 'G722'):
  666.             raise Error, 'unsupported compression type'
  667.         
  668.         self._comptype = comptype
  669.         self._compname = compname
  670.  
  671.     
  672.     def getcomptype(self):
  673.         return self._comptype
  674.  
  675.     
  676.     def getcompname(self):
  677.         return self._compname
  678.  
  679.     
  680.     def setparams(self, .2):
  681.         (nchannels, sampwidth, framerate, nframes, comptype, compname) = .2
  682.         if self._nframeswritten:
  683.             raise Error, 'cannot change parameters after starting to write'
  684.         
  685.         if comptype not in ('NONE', 'ULAW', 'ALAW', 'G722'):
  686.             raise Error, 'unsupported compression type'
  687.         
  688.         self.setnchannels(nchannels)
  689.         self.setsampwidth(sampwidth)
  690.         self.setframerate(framerate)
  691.         self.setnframes(nframes)
  692.         self.setcomptype(comptype, compname)
  693.  
  694.     
  695.     def getparams(self):
  696.         if not (self._nchannels) and not (self._sampwidth) or not (self._framerate):
  697.             raise Error, 'not all parameters set'
  698.         
  699.         return (self._nchannels, self._sampwidth, self._framerate, self._nframes, self._comptype, self._compname)
  700.  
  701.     
  702.     def setmark(self, id, pos, name):
  703.         if id <= 0:
  704.             raise Error, 'marker ID must be > 0'
  705.         
  706.         if pos < 0:
  707.             raise Error, 'marker position must be >= 0'
  708.         
  709.         if type(name) != type(''):
  710.             raise Error, 'marker name must be a string'
  711.         
  712.         for i in range(len(self._markers)):
  713.             if id == self._markers[i][0]:
  714.                 self._markers[i] = (id, pos, name)
  715.                 return None
  716.                 continue
  717.         
  718.         self._markers.append((id, pos, name))
  719.  
  720.     
  721.     def getmark(self, id):
  722.         for marker in self._markers:
  723.             if id == marker[0]:
  724.                 return marker
  725.                 continue
  726.         
  727.         raise Error, 'marker %r does not exist' % (id,)
  728.  
  729.     
  730.     def getmarkers(self):
  731.         if len(self._markers) == 0:
  732.             return None
  733.         
  734.         return self._markers
  735.  
  736.     
  737.     def tell(self):
  738.         return self._nframeswritten
  739.  
  740.     
  741.     def writeframesraw(self, data):
  742.         self._ensure_header_written(len(data))
  743.         nframes = len(data) / self._sampwidth * self._nchannels
  744.         if self._convert:
  745.             data = self._convert(data)
  746.         
  747.         self._file.write(data)
  748.         self._nframeswritten = self._nframeswritten + nframes
  749.         self._datawritten = self._datawritten + len(data)
  750.  
  751.     
  752.     def writeframes(self, data):
  753.         self.writeframesraw(data)
  754.         if self._nframeswritten != self._nframes or self._datalength != self._datawritten:
  755.             self._patchheader()
  756.         
  757.  
  758.     
  759.     def close(self):
  760.         self._ensure_header_written(0)
  761.         if self._datawritten & 1:
  762.             self._file.write(chr(0))
  763.             self._datawritten = self._datawritten + 1
  764.         
  765.         self._writemarkers()
  766.         if self._nframeswritten != self._nframes and self._datalength != self._datawritten or self._marklength:
  767.             self._patchheader()
  768.         
  769.         if self._comp:
  770.             self._comp.CloseCompressor()
  771.             self._comp = None
  772.         
  773.         self._file.flush()
  774.         self._file = None
  775.  
  776.     
  777.     def _comp_data(self, data):
  778.         import cl
  779.         dummy = self._comp.SetParam(cl.FRAME_BUFFER_SIZE, len(data))
  780.         dummy = self._comp.SetParam(cl.COMPRESSED_BUFFER_SIZE, len(data))
  781.         return self._comp.Compress(self._nframes, data)
  782.  
  783.     
  784.     def _lin2ulaw(self, data):
  785.         import audioop
  786.         return audioop.lin2ulaw(data, 2)
  787.  
  788.     
  789.     def _lin2adpcm(self, data):
  790.         import audioop
  791.         if not hasattr(self, '_adpcmstate'):
  792.             self._adpcmstate = None
  793.         
  794.         (data, self._adpcmstate) = audioop.lin2adpcm(data, 2, self._adpcmstate)
  795.         return data
  796.  
  797.     
  798.     def _ensure_header_written(self, datasize):
  799.         if not self._nframeswritten:
  800.             if self._comptype in ('ULAW', 'ALAW'):
  801.                 if not self._sampwidth:
  802.                     self._sampwidth = 2
  803.                 
  804.                 if self._sampwidth != 2:
  805.                     raise Error, 'sample width must be 2 when compressing with ULAW or ALAW'
  806.                 
  807.             
  808.             if self._comptype == 'G722':
  809.                 if not self._sampwidth:
  810.                     self._sampwidth = 2
  811.                 
  812.                 if self._sampwidth != 2:
  813.                     raise Error, 'sample width must be 2 when compressing with G7.22 (ADPCM)'
  814.                 
  815.             
  816.             if not self._nchannels:
  817.                 raise Error, '# channels not specified'
  818.             
  819.             if not self._sampwidth:
  820.                 raise Error, 'sample width not specified'
  821.             
  822.             if not self._framerate:
  823.                 raise Error, 'sampling rate not specified'
  824.             
  825.             self._write_header(datasize)
  826.         
  827.  
  828.     
  829.     def _init_compression(self):
  830.         if self._comptype == 'G722':
  831.             self._convert = self._lin2adpcm
  832.             return None
  833.         
  834.         
  835.         try:
  836.             import cl
  837.         except ImportError:
  838.             if self._comptype == 'ULAW':
  839.                 
  840.                 try:
  841.                     import audioop
  842.                     self._convert = self._lin2ulaw
  843.                     return None
  844.                 except ImportError:
  845.                     pass
  846.                 except:
  847.                     None<EXCEPTION MATCH>ImportError
  848.                 
  849.  
  850.             None<EXCEPTION MATCH>ImportError
  851.             raise Error, 'cannot write compressed AIFF-C files'
  852.  
  853.         if self._comptype == 'ULAW':
  854.             scheme = cl.G711_ULAW
  855.         elif self._comptype == 'ALAW':
  856.             scheme = cl.G711_ALAW
  857.         else:
  858.             raise Error, 'unsupported compression type'
  859.         self._comp = cl.OpenCompressor(scheme)
  860.         params = [
  861.             cl.ORIGINAL_FORMAT,
  862.             0,
  863.             cl.BITS_PER_COMPONENT,
  864.             self._sampwidth * 8,
  865.             cl.FRAME_RATE,
  866.             self._framerate,
  867.             cl.FRAME_BUFFER_SIZE,
  868.             100,
  869.             cl.COMPRESSED_BUFFER_SIZE,
  870.             100]
  871.         if self._nchannels == 1:
  872.             params[1] = cl.MONO
  873.         elif self._nchannels == 2:
  874.             params[1] = cl.STEREO_INTERLEAVED
  875.         else:
  876.             raise Error, 'cannot compress more than 2 channels'
  877.         self._comp.SetParams(params)
  878.         dummy = self._comp.Compress(0, '')
  879.         self._convert = self._comp_data
  880.  
  881.     
  882.     def _write_header(self, initlength):
  883.         if self._aifc and self._comptype != 'NONE':
  884.             self._init_compression()
  885.         
  886.         self._file.write('FORM')
  887.         if not self._nframes:
  888.             self._nframes = initlength / self._nchannels * self._sampwidth
  889.         
  890.         self._datalength = self._nframes * self._nchannels * self._sampwidth
  891.         if self._datalength & 1:
  892.             self._datalength = self._datalength + 1
  893.         
  894.         if self._aifc:
  895.             if self._comptype in ('ULAW', 'ALAW'):
  896.                 self._datalength = self._datalength / 2
  897.                 if self._datalength & 1:
  898.                     self._datalength = self._datalength + 1
  899.                 
  900.             elif self._comptype == 'G722':
  901.                 self._datalength = (self._datalength + 3) / 4
  902.                 if self._datalength & 1:
  903.                     self._datalength = self._datalength + 1
  904.                 
  905.             
  906.         
  907.         self._form_length_pos = self._file.tell()
  908.         commlength = self._write_form_length(self._datalength)
  909.         if self._aifc:
  910.             self._file.write('AIFC')
  911.             self._file.write('FVER')
  912.             _write_long(self._file, 4)
  913.             _write_long(self._file, self._version)
  914.         else:
  915.             self._file.write('AIFF')
  916.         self._file.write('COMM')
  917.         _write_long(self._file, commlength)
  918.         _write_short(self._file, self._nchannels)
  919.         self._nframes_pos = self._file.tell()
  920.         _write_long(self._file, self._nframes)
  921.         _write_short(self._file, self._sampwidth * 8)
  922.         _write_float(self._file, self._framerate)
  923.         if self._aifc:
  924.             self._file.write(self._comptype)
  925.             _write_string(self._file, self._compname)
  926.         
  927.         self._file.write('SSND')
  928.         self._ssnd_length_pos = self._file.tell()
  929.         _write_long(self._file, self._datalength + 8)
  930.         _write_long(self._file, 0)
  931.         _write_long(self._file, 0)
  932.  
  933.     
  934.     def _write_form_length(self, datalength):
  935.         if self._aifc:
  936.             commlength = 18 + 5 + len(self._compname)
  937.             if commlength & 1:
  938.                 commlength = commlength + 1
  939.             
  940.             verslength = 12
  941.         else:
  942.             commlength = 18
  943.             verslength = 0
  944.         _write_long(self._file, 4 + verslength + self._marklength + 8 + commlength + 16 + datalength)
  945.         return commlength
  946.  
  947.     
  948.     def _patchheader(self):
  949.         curpos = self._file.tell()
  950.         if self._datawritten & 1:
  951.             datalength = self._datawritten + 1
  952.             self._file.write(chr(0))
  953.         else:
  954.             datalength = self._datawritten
  955.         if datalength == self._datalength and self._nframes == self._nframeswritten and self._marklength == 0:
  956.             self._file.seek(curpos, 0)
  957.             return None
  958.         
  959.         self._file.seek(self._form_length_pos, 0)
  960.         dummy = self._write_form_length(datalength)
  961.         self._file.seek(self._nframes_pos, 0)
  962.         _write_long(self._file, self._nframeswritten)
  963.         self._file.seek(self._ssnd_length_pos, 0)
  964.         _write_long(self._file, datalength + 8)
  965.         self._file.seek(curpos, 0)
  966.         self._nframes = self._nframeswritten
  967.         self._datalength = datalength
  968.  
  969.     
  970.     def _writemarkers(self):
  971.         if len(self._markers) == 0:
  972.             return None
  973.         
  974.         self._file.write('MARK')
  975.         length = 2
  976.         for marker in self._markers:
  977.             (id, pos, name) = marker
  978.             length = length + len(name) + 1 + 6
  979.             if len(name) & 1 == 0:
  980.                 length = length + 1
  981.                 continue
  982.         
  983.         _write_long(self._file, length)
  984.         self._marklength = length + 8
  985.         _write_short(self._file, len(self._markers))
  986.         for marker in self._markers:
  987.             (id, pos, name) = marker
  988.             _write_short(self._file, id)
  989.             _write_long(self._file, pos)
  990.             _write_string(self._file, name)
  991.         
  992.  
  993.  
  994.  
  995. def open(f, mode = None):
  996.     if mode is None:
  997.         if hasattr(f, 'mode'):
  998.             mode = f.mode
  999.         else:
  1000.             mode = 'rb'
  1001.     
  1002.     if mode in ('r', 'rb'):
  1003.         return Aifc_read(f)
  1004.     elif mode in ('w', 'wb'):
  1005.         return Aifc_write(f)
  1006.     else:
  1007.         raise Error, "mode must be 'r', 'rb', 'w', or 'wb'"
  1008.  
  1009. openfp = open
  1010. if __name__ == '__main__':
  1011.     import sys
  1012.     if not sys.argv[1:]:
  1013.         sys.argv.append('/usr/demos/data/audio/bach.aiff')
  1014.     
  1015.     fn = sys.argv[1]
  1016.     f = open(fn, 'r')
  1017.     print 'Reading', fn
  1018.     print 'nchannels =', f.getnchannels()
  1019.     print 'nframes   =', f.getnframes()
  1020.     print 'sampwidth =', f.getsampwidth()
  1021.     print 'framerate =', f.getframerate()
  1022.     print 'comptype  =', f.getcomptype()
  1023.     print 'compname  =', f.getcompname()
  1024.     if sys.argv[2:]:
  1025.         gn = sys.argv[2]
  1026.         print 'Writing', gn
  1027.         g = open(gn, 'w')
  1028.         g.setparams(f.getparams())
  1029.         while 1:
  1030.             data = f.readframes(1024)
  1031.             if not data:
  1032.                 break
  1033.             
  1034.             g.writeframes(data)
  1035.         g.close()
  1036.         f.close()
  1037.         print 'Done.'
  1038.     
  1039.  
  1040.